Skip to content

Move pathfinder to cuda-python top level #723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 87 commits into from
Jul 15, 2025

Conversation

rwgk
Copy link
Collaborator

@rwgk rwgk commented Jun 24, 2025

Description

Closes #719, #708


Note: The name is changed from path_finder to pathfinder. The word "pathfinder" is very common, and it avoids underscore/dash confusion between directory names and package names.


  • Move cuda.bindings.path_findercuda.pathfinder, with backward compatibility: cuda.bindings.path_finder forwards to cuda.pathfinder.

    • Make LoadedDL._handle private (underscore prefix). It is now a platform-agnostic unsigned integer.
  • Make cuda-bindings dependent on cuda-pathfinder, with a temporary backward compatibility layer. — cuda.bindings.pathfinder is slated to be removed after the next cuda-bindings release.

  • Remove 32-bit DLL names from SUPPORTED_WINDOWS_DLLS and add runtime guard in cuda.pathfinder.load_nvidia_dynamic_lib(): "requires 64-bit Python".

  • Add specific DynamicLibNotFoundError exception type to public API (this was RuntimeError before; now inherits from RuntimeError).

  • Run mypy-pathfinder from pre-commit (after systematic mypy cleanup of library code).

  • Adjust GitHub Actions jobs to the move.

  • Add nvidia_wheels_cu12 to [project.optional-dependencies] in cuda_pathfinder/pyproject.toml and ensure all libs are loaded successfully. Treat all NVIDIA libs as "supported".

  • Mark cuda.pathfinder as version 1.0.0

Copy link
Contributor

copy-pr-bot bot commented Jun 24, 2025

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@leofang leofang self-requested a review June 24, 2025 12:51
@leofang leofang added cuda.pathfinder Everything related to the cuda.pathfinder module enhancement Any code-related improvements P0 High priority - Must do! labels Jun 24, 2025
@rwgk rwgk changed the title Move path_finder to cuda-python top level Move pathfinder to cuda-python top level Jun 24, 2025
Comment on lines 11 to 23
def load_nvidia_dynamic_lib(libname: str) -> LoadedDL:
"""Load a NVIDIA dynamic library by name.

Args:
libname: The name of the library to load (e.g. "cudart", "nvvm", etc.)

Returns:
A LoadedDL object containing the library handle and path

Raises:
RuntimeError: If the library cannot be found or loaded
"""
return _load_nvidia_dynamic_lib.load_lib(libname)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could define this wrapper function in the _dynamic_libs module and just import it here. This way your __init__.py here wouldn't have a ton of function definitions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is meant to be the public API in one view.

This way your __init__.py here wouldn't have a ton of function definitions.

I understood exactly that was your goal: a flat list of available APIs.

Note that I moved the docstring here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is meant to be the public API in one view.

Indeed, everything we define (or import) here that is not prefixed with _ constitutes the public API of the module cuda.path_finder. My above suggestion is just that we import load_nvidia_dynamic_lib rather than define it here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the public API far less obvious. E.g. to see the docstring, they'd need to open a private file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's true. They could still do:

from cuda.path_finder import load_nvidia_dynamic_lib
help(load_nvidia_dynamic_lib)

Same as they would do now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'll only work interactively.

What I have now can be inspected in obvious ways directly in the sources, e.g. when looking at the sources on github. I can send URLs pointing to specific APIs in this init.py file.

Each function here will just be:

def function(...) -> ...:
    """docstring""
    return call_into_private_code(...)

That's exactly the public API, with a one-line call that's easy to ignore.

What's the point of hiding that away, especially hiding away the docstring and the type hints?

Copy link
Contributor

@shwina shwina Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'll only work interactively.

The docstrings and type hints would also get picked up:

  • Sphinx (which we use to generate API docs
    -pydoc
  • the developers' IDEs/lsp

Those are primarily the ways consumers of a package interact with docstrings or type hints, rather than looking directly at the source.

What's the point of hiding that away, especially hiding away the docstring and the type hints?

It tightens the scope of __init__.py, whose job is:

  • to include any initialization code for the module
  • to import stuff from submodules that the module wants to expose
  • to define __all__ for the module if needed

As examples, we can look at the __init__.py from some other popular libraries:

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It tightens the scope of init.py, whose job is

The most important job: Show the public API

You didn't answer why you want to hide that away.

Copy link
Contributor

@shwina shwina Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm advocating for keeping function and type definitions outside of __init__.py. I don't think that "hides" anything from the user as we still import them here.

The main reason I'm advocating for that is because __init__.py typically only defines functions and types needed for module initialization, and imports anything else. I think the examples I linked to above are a good demonstration of that.

Defining functions and types beyond that serves to clutter __init__.py.

I would argue it makes the code base less navigable than more for people looking at the source. Do I expect the function load_nvidia_dynamic_libs to be defined in a file called _dynamic_libs.py, or a file called __init__.py?

If this all seems nitpicky, I apologize. While I do have a strong opinion here, I don't mind at all if another reviewer (or you, as the author of this PR) made the final call about this.

Copy link
Member

@leofang leofang Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cuda.core's __init__.py is a good example for what Ashwin suggested. As a developer who occasionally peeks into someone else's __init__.py, I certainly get confused why we are defining things in there directly, as opposed to properly organizing them in respective public/private modules, and just import them. What's imported are considered public APIs (including types). Does it make sense?

@rwgk
Copy link
Collaborator Author

rwgk commented Jun 25, 2025

I'm a bit lost, to be honest, and I’d appreciate some clarification so I can move this forward in the direction you want.

The goals that seemed most important to me originally (from a Slack post last Wednesday) were:

  1. Dependency isolation – avoid importing unrelated logic (e.g. dynamic lib loading) when only working with headers
  2. Public API should be obvious from the code – minimal need for external docs or tooling to understand what’s exposed

After Ashwin’s comment on Slack, I interpreted the request as: prioritize a flat public API, even if that means giving up on some of that isolation — especially when type hints are involved.

Then Leo wrote:

as opposed to properly organizing them in respective public/private modules

That seems more aligned with what I had before the last commit (e.g., a file like nvidia_dynamic_libs.py directly under pathfinder/). But that seemed in conflict with Ashwin’s preference for flatness.

I’m happy to implement what you both want here — I just need a bit more clarity.

If we go back to what I proposed last week:

from cuda.pathfinder import nvidia_dynamic_libs, nvidia_static_libs, nvidia_headers

nvidia_dynamic_libs.load("nvrtc")
nvidia_static_libs.find("cudart")
nvidia_headers.find_file("cuda.h")

The file structure was:

cuda/pathfinder/
├── __init__.py  # empty
├── nvidia_dynamic_libs.py
├── nvidia_static_libs.py
└── nvidia_headers.py

I thought that structure balanced modularity and clarity, and users could still import just what they needed. But it sounds like we might instead prefer:

from cuda.pathfinder import load_nvidia_dynamic_lib, find_nvidia_static_lib, find_nvidia_header_file

That keeps the API flat, but does give up on the isolation goal unless we resort to function-local imports or other workarounds.

Could you please help me understand: What would be the preferred file/module structure to go along with the flat API? Should I keep separate modules like nvidia_dynamic_libs.py and re-export in __init__.py, or move everything into a single file (what would be the name)?

@shwina
Copy link
Contributor

shwina commented Jun 25, 2025

Given there's some urgency for getting this PR in, @rwgk @leofang do you want to proceed with the PR as is and address the questions Ralf posed above as a follow-up?

@leofang
Copy link
Member

leofang commented Jun 26, 2025

At this point we need to follow up offline. I think there is a gap that we unfortunately did not really cover during the weekly meeting. I suggest we don't cancel the dev meeting tomorrow and use the time to finalize it.

This PR also needs at least @kkraus14's approval for the change of license.

@kkraus14
Copy link
Collaborator

This looks good to me, sans the one comment above about the visibility of things in the cuda.bindings.path_finder and avoiding accidentally introducing public APIs that we don't wish to support.

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 11, 2025

/ok to test

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 11, 2025

@kkraus14 I merged in main (SPDX changes) and put #751 as-is on top here: commit c0509be

Everything else is as before. I think this is ready for merging (pending completion of tests).

@leofang Merging is blocked by your request for changes, could you please help?

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 11, 2025

I just added one more commit to this PR, just one extra line: eedf658

After reading up on publishing to PyPI, I'm guessing this is all that's needed on this end to publish cuda-pathfinder wheels to PyPI?

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 12, 2025 via email

…backward_compatibility.py, to fully sanitize path_finder.py
@rwgk
Copy link
Collaborator Author

rwgk commented Jul 12, 2025

/ok to test

kkraus14
kkraus14 previously approved these changes Jul 14, 2025
rwgk added 3 commits July 14, 2025 12:19
- Move mypy configuration from cuda_pathfinder/mypy.ini to [tool.mypy] section in pyproject.toml
- Delete cuda_pathfinder/mypy.ini file
- Update .pre-commit-config.yaml to point to pyproject.toml for mypy configuration
- Maintain identical functionality with consolidated config

Addresses review comment about preferring pyproject.toml over separate ini files.
…ersion release."

Also fix pathfinder → path_finder oversights.
@rwgk
Copy link
Collaborator Author

rwgk commented Jul 14, 2025

I'm not rerunning the CI:

  • pre-commit.ci exercises the pyproject.toml changes.
  • All other changes only affect comments and documentation.

Copy link
Member

@leofang leofang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for pushing this forward Ralf!

btw I skipped reviewing commit c0509be from #751, unfortunately it's too much for me to review at once. In the future I'd appreciate we follow what we did in the past and have a series of smaller PRs with a focused scope.

@@ -286,6 +292,11 @@ jobs:
- name: Set up compute-sanitizer
run: setup-sanitizer

- name: Run cuda.pathfinder tests with see_what_works
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Later the pathfinder will need to check the driver version, so the status quo is fine.

Comment on lines +54 to +55
if dll.startswith("nvrtc-builtins"):
return True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I just forget what "suppressed DLLs" means...

Comment on lines +64 to +65
pointer_size_bits = struct.calcsize("P") * 8
if pointer_size_bits != 64:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI usually we can check this with sys.maxsize > 2**32:
https://docs.python.org/3/library/platform.html#platform.architecture

@github-project-automation github-project-automation bot moved this from In Progress to In Review in CCCL Jul 15, 2025
@leofang
Copy link
Member

leofang commented Jul 15, 2025

btw @rwgk could you create an issue to track the need to add docs for pathfinder? We need a Sphinx-rendered docs.

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 15, 2025

/ok to test

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 15, 2025

btw I skipped reviewing commit c0509be from #751, unfortunately it's too much for me to review at once. In the future I'd appreciate we follow what we did in the past and have a series of smaller PRs with a focused scope.

Just to explain, that's my preferred work style, too, but two things led to the current situation:

@rwgk rwgk merged commit ed12c83 into NVIDIA:main Jul 15, 2025
53 checks passed
@github-project-automation github-project-automation bot moved this from In Review to Done in CCCL Jul 15, 2025
@rwgk rwgk deleted the move_path_finder_to_top branch July 15, 2025 20:52
Copy link

Doc Preview CI
Preview removed because the pull request was closed or merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cuda.pathfinder Everything related to the cuda.pathfinder module enhancement Any code-related improvements P0 High priority - Must do!
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[FEA]: Move path_finder to cuda-python top level
4 participants